unit Results;

interface

uses
  Classes,
  GlobalRecordsAndEnums, Items, Decryptor, Location;

type
  TConfiguration = class;

  TResult = class
    private
      _item: TNewItem;
      _configuration: TConfiguration;
      _success: Boolean;
      _date: TDateTime;
    public
      constructor Create(item: TNewItem; configuration: TConfiguration; success: Boolean; date: TDateTime = 0);

      property Item: TNewItem read _item;
      property Configuration: TConfiguration read _configuration;
      property Success: Boolean read _success;
      property Date: TDateTime read _date;
  end;
  TResultsList = array of TResult;

  TConfiguration = class
    private
      _name: String;
      _id: Integer;
      _decryptortype: TDecryptorType;
      _metalevel: Integer;
      _bpcmaxruns: Boolean;
      _bpcruns: Integer;
      _bpcme: Integer;
      _bpcpe: Integer;
      _location: TLocation;
    public
      constructor Create(name: String; id: Integer; decryptortype: TDecryptorType; metalevel: Integer; maxbpcruns: Boolean; bpcruns: Integer; bpcme: Integer; bpcpe: Integer; location: TLocation);

      property Name: String read _name;
      property ID: Integer read _id;
      property DecryptorType: TDecryptorType read _decryptortype;
      property MetaLevel: Integer read _metalevel;
      property BPCMaxRuns: Boolean read _bpcmaxruns;
      property BPCRuns: Integer read _bpcruns;
      property BPCME: Integer read _bpcme;
      property BPCPE: Integer read _bpcpe;
      property Location: TLocation read _location;
  end;
  TConfigurationList = array of TConfiguration;

  SConfigurationResult = record
    Configuration: TConfiguration;
    Amount: Integer;
    Successes: Integer;
    Failures: Integer;
    SuccessPercentage: Double;
  end;
  SConfigurationResultList = array of SConfigurationResult;

  TResults = class
    private
      _startdate: TDateTime;
      _enddate: TDateTime;

      _results: TList;
      _configurations: TList;

      function GetResultCount: Integer;
      function GetConfigurationCount: Integer;
    public
      constructor Create;
      destructor Destroy; reintroduce;

      procedure AddResult(item: TNewItem; configuration: TConfiguration; success: Boolean; date: TDateTime = 0);
      function GetResults(item: TNewItem): TResultsList; overload;
      function GetResults(configuration: TConfiguration): TResultsList; overload;
      function GetResultItems: TNewItemsList;
      procedure RemoveResult(item: TNewItem; configuration: TConfiguration; successes, failures: Integer; removeconfiguration: Boolean);

      procedure AddConfiguration(name: String; decryptortype: TDecryptorType; metalevel: Integer; maxbpcruns: Boolean; bpcruns: Integer; bpcme: Integer; bpcpe: Integer; location: TLocation);
      function GetConfigurationByIndex(index: Integer): TConfiguration;
      function GetConfiguration(id: Integer): TConfiguration;

      procedure Save;
      procedure Clear;

      property ResultCount: Integer read GetResultCount;
      property ConfigurationCount: Integer read GetConfigurationCount;
  end;
  function SortConfigurations(Item1, Item2: Pointer): Integer;

implementation

uses
  SysUtils, Dialogs;

//=====================
//====== TResult ======
//=====================

constructor TResult.Create(item: TNewItem; configuration: TConfiguration; success: Boolean; date: TDateTime = 0);
begin
  inherited Create;
  _item := item;
  _configuration := configuration;
  _success := success;
  if (date = 0) then _date := Now
  else _date := date;
end;

//============================
//====== TConfiguration ======
//============================

constructor TConfiguration.Create(name: String; id: Integer; decryptortype: TDecryptorType; metalevel: Integer; maxbpcruns: Boolean; bpcruns: Integer; bpcme: Integer; bpcpe: Integer; location: TLocation);
begin
  _name := name;
  _id := id;
  _decryptortype := decryptortype;
  _metalevel := metalevel;
  _bpcmaxruns :=  maxbpcruns;
  _bpcruns := bpcruns;
  _bpcme := bpcme;
  _bpcpe := bpcpe;
  _location := location;
end;

//======================
//====== TResults ======
//======================

function TResults.GetResultCount: Integer;
begin
  result := _results.Count;
end;

function TResults.GetConfigurationCount: Integer;
begin
  result := _configurations.Count;
end;

constructor TResults.Create;
begin
  inherited Create;
  _results := TList.Create;
  _configurations := TList.Create;
end;

destructor TResults.Destroy;
var
  i: Integer;
begin
  for i := 0 to _results.Count -1 do begin
    TResult(_results[i]).Destroy;
  end;
  _results.Destroy;
  for i := 0 to _configurations.Count -1 do begin
    TConfiguration(_configurations[i]).Destroy;
  end;
  _configurations.Destroy;
end;

procedure TResults.AddResult(item: TNewItem; configuration: TConfiguration; success: Boolean; date: TDateTime = 0);
begin
  _results.Add(TResult.Create(item, configuration, success, date));
end;

function TResults.GetResults(item: TNewItem): TResultsList;
// returns invention results of a specific item
var
  i, len: Integer;
  resultitem: TResult;
begin
  SetLength(result, 0);
  for i := 0 to _results.Count -1 do begin
    resultitem := TResult(_results[i]);
    if (resultitem.Item = item) then begin
      len := Length(result);
      SetLength(result, len +1);
      result[len] := resultitem;
    end;
  end;
end;

function TResults.GetResults(configuration: TConfiguration): TResultsList;
// returns invention results of a specific configuration
var
  i, len: Integer;
  resultitem: TResult;
begin
  SetLength(result, 0);
  for i := 0 to _results.Count -1 do begin
    resultitem := TResult(_results[i]);
    if (resultitem.Configuration = configuration) then begin
      len := Length(result);
      SetLength(result, len +1);
      result[len] := resultitem;
    end;
  end;
end;
function TResults.GetResultItems: TNewItemsList;
// returns the TNewItems that have invention results
var
  i, j, len: Integer;
  resultitem: TResult;
  alreadyreturned: Boolean;
begin
  SetLength(result, 0);
  for i := 0 to _results.Count -1 do begin
    resultitem := TResult(_results[i]);
    alreadyreturned := false;
    for j := 0 to Length(result) -1 do begin
      if (result[j] = resultitem.Item) then begin
        alreadyreturned := true;
      end;
    end;
    if (not alreadyreturned) then begin
      len := Length(result);
      SetLength(result, len +1);
      result[len] := resultitem.Item;
    end;
  end;
end;

procedure TResults.RemoveResult(item: TNewItem; configuration: TConfiguration; successes, failures: Integer; removeconfiguration: Boolean);
var
  i, len: Integer;
  result: TResult;
  suc, fail: Integer;
  resultstoremove: TResultsList;
begin
  suc := successes;
  fail := failures;
  for i := 0 to _results.Count -1 do begin
    result := TResult(_results[i]);
    if ((result.Item = item) and (result.Configuration = configuration)) then begin
      if ((result.Success) and (suc > 0)) then begin
        len := Length(resultstoremove);
        Setlength(resultstoremove, len +1);
        resultstoremove[len] := result;
        suc := suc - 1;
      end;
      if ((not result.Success) and (fail > 0)) then begin
        len := Length(resultstoremove);
        Setlength(resultstoremove, len +1);
        resultstoremove[len] := result;
        fail := fail -1;
      end;
    end;
    if ((suc = 0) and (fail = 0)) then break;
  end;
  for i := 0 to Length(resultstoremove) -1 do begin
    _results.Remove(resultstoremove[i]);
    resultstoremove[i].Destroy;
  end;
  if (removeconfiguration) then begin
    if (Length(GetResults(configuration)) = 0) then begin
      _configurations.Remove(configuration);
      configuration.Destroy;
    end;
  end;
end;

procedure TResults.AddConfiguration(name: String; decryptortype: TDecryptorType; metalevel: Integer; maxbpcruns: Boolean; bpcruns: Integer; bpcme: Integer; bpcpe: Integer; location: TLocation);
var
  i, id: Integer;
begin
  _configurations.Sort(SortConfigurations);
  id := 0;
  for i := 0 to _configurations.Count -1 do begin
    id := id + 1;
    if (TConfiguration(_configurations[i]).ID > id) then break;
  end;
  _configurations.Add(TConfiguration.Create(name, id, decryptortype, metalevel, maxbpcruns, bpcruns, bpcme, bpcpe, location));
end;

function SortConfigurations(Item1, Item2: Pointer): Integer;
begin
  result := CompareText(TConfiguration(Item1).Name, TConfiguration(Item2).Name);
end;

function TResults.GetConfigurationByIndex(index: Integer): TConfiguration;
begin
  if (index < _configurations.Count) then result := _configurations[index]
  else result := nil;
end;

function TResults.GetConfiguration(id: Integer): TConfiguration;
var
  i: Integer;
begin
  result := nil;
  for i := 0 to _configurations.Count -1 do begin
    if (TConfiguration(_configurations[i]).ID = id) then result := TConfiguration(_configurations[i]);
  end;
end;

procedure TResults.Save;
var
  i: Integer;
  stream: TMemoryStream;
  configcount: Integer;
  configuration: TConfiguration;
  config: SConfiguration;
  result: TResult;
  res: SResult;
  version: Double;
begin
  version := 0.41;
  stream := TMemoryStream.Create;
  stream.Write(version, SizeOf(Double));
  configcount := _configurations.Count;
  stream.Write(configcount, SizeOf(Integer));
  for i := 0 to _configurations.Count -1 do begin
    configuration := TConfiguration(_configurations[i]);
    config.Name := configuration.Name;
    config.ID := configuration.ID;
    if (configuration.DecryptorType = nil) then config.DecryptorTypeID := -1
    else config.DecryptorTypeID := configuration.DecryptorType.ID;
    config.Metalevel := configuration.MetaLevel;
    config.BPCMaxRuns := configuration.BPCMaxRuns;
    config.BPCRuns := configuration.BPCRuns;
    config.BPCME := configuration.BPCME;
    config.BPCPE := configuration.BPCPE;
    config.LocationID := configuration.Location.ID;
    stream.Write(config, SizeOf(SConfiguration));
  end;
  for i := 0 to _results.Count -1 do begin
    result := TResult(_results[i]);
    res.ItemID := result.Item.ID;
    res.ConfigurationID := result.Configuration.ID;
    res.Success := result.Success;
    res.Date := result.Date;
    stream.Write(res, SizeOf(SResult));
  end;
  try
    stream.SaveToFile('user\InventionResults.dat');
  except
    on e: Exception do MessageDlg(e.Message, mtError, [mbOk], 0);
  end;
  stream.Free;
end;

procedure TResults.Clear;
var
  i: Integer;
begin
  for i := 0 to _results.Count -1 do begin
    TResult(_results[i]).Destroy;
  end;
  _results.Destroy;
  for i := 0 to _configurations.Count -1 do begin
    TConfiguration(_configurations[i]).Destroy;
  end;
  _configurations.Destroy;

  _results := TList.Create;
  _configurations := TList.Create;
end;

end.
